#if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR) #pragma warning disable using System; using System.Collections; using System.IO; using BestHTTP.SecureProtocol.Org.BouncyCastle.Asn1.X509; using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Agreement.Srp; using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Parameters; using BestHTTP.SecureProtocol.Org.BouncyCastle.Math; using BestHTTP.SecureProtocol.Org.BouncyCastle.Security; using BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities; using BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities.IO; namespace BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Tls { /// <summary>(D)TLS SRP key exchange (RFC 5054).</summary> public class TlsSrpKeyExchange : AbstractTlsKeyExchange { protected static TlsSigner CreateSigner(int keyExchange) { switch (keyExchange) { case KeyExchangeAlgorithm.SRP: return null; case KeyExchangeAlgorithm.SRP_RSA: return new TlsRsaSigner(); case KeyExchangeAlgorithm.SRP_DSS: return new TlsDssSigner(); default: throw new ArgumentException("unsupported key exchange algorithm"); } } protected TlsSigner mTlsSigner; protected TlsSrpGroupVerifier mGroupVerifier; protected byte[] mIdentity; protected byte[] mPassword; protected AsymmetricKeyParameter mServerPublicKey = null; protected Srp6GroupParameters mSrpGroup = null; protected Srp6Client mSrpClient = null; protected Srp6Server mSrpServer = null; protected BigInteger mSrpPeerCredentials = null; protected BigInteger mSrpVerifier = null; protected byte[] mSrpSalt = null; protected TlsSignerCredentials mServerCredentials = null; [Obsolete("Use constructor taking an explicit 'groupVerifier' argument")] public TlsSrpKeyExchange(int keyExchange, IList supportedSignatureAlgorithms, byte[] identity, byte[] password) : this(keyExchange, supportedSignatureAlgorithms, new DefaultTlsSrpGroupVerifier(), identity, password) { } public TlsSrpKeyExchange(int keyExchange, IList supportedSignatureAlgorithms, TlsSrpGroupVerifier groupVerifier, byte[] identity, byte[] password) : base(keyExchange, supportedSignatureAlgorithms) { this.mTlsSigner = CreateSigner(keyExchange); this.mGroupVerifier = groupVerifier; this.mIdentity = identity; this.mPassword = password; this.mSrpClient = new Srp6Client(); } public TlsSrpKeyExchange(int keyExchange, IList supportedSignatureAlgorithms, byte[] identity, TlsSrpLoginParameters loginParameters) : base(keyExchange, supportedSignatureAlgorithms) { this.mTlsSigner = CreateSigner(keyExchange); this.mIdentity = identity; this.mSrpServer = new Srp6Server(); this.mSrpGroup = loginParameters.Group; this.mSrpVerifier = loginParameters.Verifier; this.mSrpSalt = loginParameters.Salt; } public override void Init(TlsContext context) { base.Init(context); if (this.mTlsSigner != null) { this.mTlsSigner.Init(context); } } public override void SkipServerCredentials() { if (mTlsSigner != null) throw new TlsFatalAlert(AlertDescription.unexpected_message); } public override void ProcessServerCertificate(Certificate serverCertificate) { if (mTlsSigner == null) throw new TlsFatalAlert(AlertDescription.unexpected_message); if (serverCertificate.IsEmpty) throw new TlsFatalAlert(AlertDescription.bad_certificate); X509CertificateStructure x509Cert = serverCertificate.GetCertificateAt(0); SubjectPublicKeyInfo keyInfo = x509Cert.SubjectPublicKeyInfo; try { this.mServerPublicKey = PublicKeyFactory.CreateKey(keyInfo); } catch (Exception e) { throw new TlsFatalAlert(AlertDescription.unsupported_certificate, e); } if (!mTlsSigner.IsValidPublicKey(this.mServerPublicKey)) throw new TlsFatalAlert(AlertDescription.certificate_unknown); TlsUtilities.ValidateKeyUsage(x509Cert, KeyUsage.DigitalSignature); base.ProcessServerCertificate(serverCertificate); } public override void ProcessServerCredentials(TlsCredentials serverCredentials) { if ((mKeyExchange == KeyExchangeAlgorithm.SRP) || !(serverCredentials is TlsSignerCredentials)) throw new TlsFatalAlert(AlertDescription.internal_error); ProcessServerCertificate(serverCredentials.Certificate); this.mServerCredentials = (TlsSignerCredentials)serverCredentials; } public override bool RequiresServerKeyExchange { get { return true; } } public override byte[] GenerateServerKeyExchange() { mSrpServer.Init(mSrpGroup, mSrpVerifier, TlsUtilities.CreateHash(HashAlgorithm.sha1), mContext.SecureRandom); BigInteger B = mSrpServer.GenerateServerCredentials(); ServerSrpParams srpParams = new ServerSrpParams(mSrpGroup.N, mSrpGroup.G, mSrpSalt, B); DigestInputBuffer buf = new DigestInputBuffer(); srpParams.Encode(buf); if (mServerCredentials != null) { /* * RFC 5246 4.7. digitally-signed element needs SignatureAndHashAlgorithm from TLS 1.2 */ SignatureAndHashAlgorithm signatureAndHashAlgorithm = TlsUtilities.GetSignatureAndHashAlgorithm( mContext, mServerCredentials); IDigest d = TlsUtilities.CreateHash(signatureAndHashAlgorithm); SecurityParameters securityParameters = mContext.SecurityParameters; d.BlockUpdate(securityParameters.clientRandom, 0, securityParameters.clientRandom.Length); d.BlockUpdate(securityParameters.serverRandom, 0, securityParameters.serverRandom.Length); buf.UpdateDigest(d); byte[] hash = new byte[d.GetDigestSize()]; d.DoFinal(hash, 0); byte[] signature = mServerCredentials.GenerateCertificateSignature(hash); DigitallySigned signed_params = new DigitallySigned(signatureAndHashAlgorithm, signature); signed_params.Encode(buf); } return buf.ToArray(); } public override void ProcessServerKeyExchange(Stream input) { SecurityParameters securityParameters = mContext.SecurityParameters; SignerInputBuffer buf = null; Stream teeIn = input; if (mTlsSigner != null) { buf = new SignerInputBuffer(); teeIn = new TeeInputStream(input, buf); } ServerSrpParams srpParams = ServerSrpParams.Parse(teeIn); if (buf != null) { DigitallySigned signed_params = ParseSignature(input); ISigner signer = InitVerifyer(mTlsSigner, signed_params.Algorithm, securityParameters); buf.UpdateSigner(signer); if (!signer.VerifySignature(signed_params.Signature)) throw new TlsFatalAlert(AlertDescription.decrypt_error); } this.mSrpGroup = new Srp6GroupParameters(srpParams.N, srpParams.G); if (!mGroupVerifier.Accept(mSrpGroup)) throw new TlsFatalAlert(AlertDescription.insufficient_security); this.mSrpSalt = srpParams.S; /* * RFC 5054 2.5.3: The client MUST abort the handshake with an "illegal_parameter" alert if * B % N = 0. */ try { this.mSrpPeerCredentials = Srp6Utilities.ValidatePublicValue(mSrpGroup.N, srpParams.B); } catch (CryptoException e) { throw new TlsFatalAlert(AlertDescription.illegal_parameter, e); } this.mSrpClient.Init(mSrpGroup, TlsUtilities.CreateHash(HashAlgorithm.sha1), mContext.SecureRandom); } public override void ValidateCertificateRequest(CertificateRequest certificateRequest) { throw new TlsFatalAlert(AlertDescription.unexpected_message); } public override void ProcessClientCredentials(TlsCredentials clientCredentials) { throw new TlsFatalAlert(AlertDescription.internal_error); } public override void GenerateClientKeyExchange(Stream output) { BigInteger A = mSrpClient.GenerateClientCredentials(mSrpSalt, mIdentity, mPassword); TlsSrpUtilities.WriteSrpParameter(A, output); mContext.SecurityParameters.srpIdentity = Arrays.Clone(mIdentity); } public override void ProcessClientKeyExchange(Stream input) { /* * RFC 5054 2.5.4: The server MUST abort the handshake with an "illegal_parameter" alert if * A % N = 0. */ try { this.mSrpPeerCredentials = Srp6Utilities.ValidatePublicValue(mSrpGroup.N, TlsSrpUtilities.ReadSrpParameter(input)); } catch (CryptoException e) { throw new TlsFatalAlert(AlertDescription.illegal_parameter, e); } mContext.SecurityParameters.srpIdentity = Arrays.Clone(mIdentity); } public override byte[] GeneratePremasterSecret() { try { BigInteger S = mSrpServer != null ? mSrpServer.CalculateSecret(mSrpPeerCredentials) : mSrpClient.CalculateSecret(mSrpPeerCredentials); // TODO Check if this needs to be a fixed size return BigIntegers.AsUnsignedByteArray(S); } catch (CryptoException e) { throw new TlsFatalAlert(AlertDescription.illegal_parameter, e); } } protected virtual ISigner InitVerifyer(TlsSigner tlsSigner, SignatureAndHashAlgorithm algorithm, SecurityParameters securityParameters) { ISigner signer = tlsSigner.CreateVerifyer(algorithm, this.mServerPublicKey); signer.BlockUpdate(securityParameters.clientRandom, 0, securityParameters.clientRandom.Length); signer.BlockUpdate(securityParameters.serverRandom, 0, securityParameters.serverRandom.Length); return signer; } } } #pragma warning restore #endif